package cn.pilipa.common.config;

import static org.assertj.core.api.Assertions.assertThat;
import static org.assertj.core.api.Assertions.fail;

import cn.pilipa.common.config.data.ObjHolder;
import com.mongodb.client.FindIterable;
import com.mongodb.client.MongoCursor;
import java.time.LocalDate;
import java.time.YearMonth;
import org.javamoney.moneta.Money;
import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.data.mongodb.core.MongoTemplate;
import org.springframework.data.mongodb.core.query.Criteria;
import org.springframework.data.mongodb.core.query.Query;
import org.springframework.test.context.ActiveProfiles;
import org.springframework.test.context.junit4.SpringRunner;

@RunWith(SpringRunner.class)
@SpringBootTest
@ActiveProfiles("integTest")
public class MongoConfigTest {

  public static final String COLLECTION_NAME = "money-test";
  @Autowired
  MongoTemplate mongoTemplate;

  public static final String yearMonthStr = "2018-04";
  public static final String localDateStr = "2018-04-16";

  public static final YearMonth yearMonth = YearMonth.of(2018, 4);
  public static final LocalDate localDate = LocalDate.of(2018, 4, 16);

  public static final Money cny = Money.of(99, "CNY");
  public static final ObjHolder objHolder = new ObjHolder("n", cny, localDate, yearMonth);

  @Before
  public void setup() {
    mongoTemplate.dropCollection(ObjHolder.class);
  }

  @Test
  public void serializeObject() throws Exception {
    mongoTemplate.insert(objHolder);

    FindIterable<org.bson.Document> iterable = mongoTemplate.getCollection(COLLECTION_NAME).find();
    MongoCursor<org.bson.Document> cursor = iterable.iterator();
    if (cursor.hasNext()) {
      org.bson.Document obj = cursor.next();
      assertThat(obj.get("_id")).isEqualTo(objHolder.getName());
      assertThat(obj.get("money")).isInstanceOf(org.bson.Document.class);

      org.bson.Document money = (org.bson.Document) obj.get("money");
      assertThat(money.get("value").toString()).isEqualTo("99");
      assertThat(money.get("currency").toString()).isEqualTo("CNY");

      assertThat(obj.get("localDate")).isEqualTo(localDateStr);
      assertThat(obj.get("yearMonth")).isEqualTo(yearMonthStr);
    } else {
      fail("Can not retrieve the object with expected id.");
    }
  }

  @Test
  public void deserializeObject() throws Exception {
    final org.bson.Document doc = new org.bson.Document();
    doc.put("_id", "j");
    doc.put("_class", ObjHolder.class.getCanonicalName());
    final org.bson.Document moneyDoc = new org.bson.Document();
    doc.put("money", moneyDoc);
    moneyDoc.put("_class", Money.class.getCanonicalName());
    moneyDoc.put("currency", "CNY");
    moneyDoc.put("value", "100.00");

    doc.put("localDate",localDateStr);
    doc.put("yearMonth",yearMonthStr);
    mongoTemplate.getCollection(COLLECTION_NAME).insertOne(doc);

    final Money oneHundred = Money.of(100, "CNY");
    final ObjHolder objHolder = mongoTemplate.findOne(
        Query.query(Criteria.where("_id").is("j")),
        ObjHolder.class
    );
    assertThat(objHolder).isNotNull();
    assertThat(objHolder.getMoney()).isEqualTo(oneHundred);

    assertThat(objHolder.getLocalDate()).isEqualTo(localDate);
    assertThat(objHolder.getYearMonth()).isEqualTo(yearMonth);
  }

}
